/*****************************************************************************
* 采用简易Lut管理
* 数据的写入必须以块为单位，也就是外部必须有完整的缓存，缓存可以是 其他flash或者ram。
* 写入时发现坏块就直接重写，连续3次判定为坏块标记为坏块不在使用，查询新块重新从缓存写入。
* 使用新的物理块是先擦除并做空检测，不通过直接标记为坏块。
*****************************************************************************/
#include "nand_lut.h"

/*****************************************************************************
* @brief   外部支持
*****************************************************************************/
char nand_power_wait(void);

/*****************************************************************************
* @brief   INFO
*****************************************************************************/
#define DEFAULT_PAGE_MAIN_SIZE 2048
#define DEFAULT_PAGE_SPARE_SIZE 64
#define DEFAULT_PAGE_SIZE (DEFAULT_PAGE_MAIN_SIZE + DEFAULT_PAGE_SPARE_SIZE)
#define DEFAULT_PAGE_PER_BLOCK 64
#define DEFAULT_BLOCK_TOTAL 1024

/*****************************************************************************
* @brief   打开LUT
*****************************************************************************/
void nand_lut_open(nand_lut_type *lut, char (*dev_link)(nand_lut_type *lut))
{
	// 默认值
	lut->page_size = DEFAULT_PAGE_SIZE;
	lut->page_main_size = DEFAULT_PAGE_MAIN_SIZE;
	lut->page_spare_size = DEFAULT_PAGE_SPARE_SIZE;
	lut->page_per_block = DEFAULT_PAGE_PER_BLOCK;
	lut->block_per_plane = DEFAULT_BLOCK_TOTAL;
	lut->block_total = DEFAULT_BLOCK_TOTAL;
	lut->logic_block_amount = DEFAULT_BLOCK_TOTAL * 7 / 8;

	// 链接设备
	dev_link(lut);

	// 申请内存
	if (lut->tab)
	{
		free(lut->tab);
	}

	if (lut->buff)
	{
		free(lut->buff);
	}

	lut->tab = malloc(lut->logic_block_amount * 2 + 16);
	if (0 == lut->tab)
		return;

	lut->buff = malloc(lut->page_main_size + lut->page_spare_size);
	if (0 == lut->buff)
	{
		free(lut->tab);
		lut->tab = 0;
		return;
	}

	//初始化
	if (lut->hal.init)
	{
		lut->hal.init();
	}

	//创建lut
	nand_lut_creat(lut);
}

/*****************************************************************************
* @brief   关闭LUT
*****************************************************************************/
void nand_lut_close(nand_lut_type *lut)
{
	// 释放内存
	if (lut->tab)
	{
		free(lut->tab);
		lut->tab = 0;
	}

	if (lut->buff)
	{
		free(lut->buff);
		lut->buff = 0;
	}
}

/*****************************************************************************
* @brief   读取信息区
*****************************************************************************/
int8_t nand_lut_info_sapre_read(
	nand_lut_type *lut, uint16_t physical_block,
	lut_spare_type *spare_head, lut_spare_type *spare_tail)
{
	int8_t read_cnt;

	// 越界检测
	if (physical_block >= lut->block_total)
	{
		memset(spare_head, 0, 8);
		memset(spare_tail, 0, 8);
		return -1;
	}

	// Spare读取，如果连续5次错误视为非法块
	read_cnt = 3;
	while (read_cnt--)
	{
		// 读取块第一页spare区, 首块未块spare必须相同
		lut->hal.read_spare(physical_block * lut->page_per_block, (uint8_t *)spare_head, 8);
		lut->hal.read_spare((physical_block + 1) * lut->page_per_block - 1, (uint8_t *)spare_tail, 8);
		if (0 == memcmp(spare_head, spare_tail, sizeof(8)))
		{
			break;
		}
	}

	return read_cnt;
}

/*****************************************************************************
* @brief   读取时间区
*****************************************************************************/
int8_t nand_lut_sapre_read(
	nand_lut_type *lut, uint16_t physical_block, uint16_t page_offset,
	lut_spare_type *spare_buff1, lut_spare_type *spare_buff2)
{
	int8_t read_cnt;

	// 越界检测
	if (physical_block >= lut->block_total)
	{
		memset(spare_buff1, 0, 8);
		memset(spare_buff2, 0, 8);
		return -1;
	}

	// Spare读取，如果连续3次错误视为非法块
	read_cnt = 3;
	while (read_cnt--)
	{
		// 读取spare区
		lut->hal.read_spare(physical_block * lut->page_per_block + page_offset, (uint8_t *)spare_buff1, 8);
		lut->hal.read_spare(physical_block * lut->page_per_block + page_offset, (uint8_t *)spare_buff2, 8);
		if (0 == memcmp(spare_buff1, spare_buff2, sizeof(8)))
		{
			break;
		}
	}

	return read_cnt;
}

/*****************************************************************************
* @brief   创建逻辑表
*****************************************************************************/
void nand_lut_creat(nand_lut_type *lut)
{
	uint16_t physical_block;
	lut_spare_type *spare_head;
	lut_spare_type *spare_tail;

	// 清空LUT
	memset(lut->tab, 0xFF, lut->logic_block_amount * 2);

	// 初始参数
	lut->new_block_next = 0xFFFF;
	lut->empty_block = 0;
	lut->bad_block = 0;
	lut->valid_block = 0;
	lut->illegal_block = 0;

	lut->update.batch_now = 0;

	// 备份区指针
	spare_head = (lut_spare_type *)&lut->buff[0];
	spare_tail = (lut_spare_type *)&lut->buff[32];

	for (physical_block = 0; physical_block < lut->block_total; physical_block++)
	{
		int8_t read_cnt;

		read_cnt = nand_lut_info_sapre_read(lut, physical_block, spare_head, spare_tail);

		// 检测坏块标记
		if (spare_head->info.bad_mark != 0xFFFF)
		{
			lut->bad_block++;
			lut_print("nand found bad block, block address: %d\n", physical_block);
			continue;
		}

		// 本驱动有写入后读回校验，非物理损伤(包括强电磁辐射)情况下，不会出现Spare无效
		// 无效spare ,且不是坏块，擦除回收
		if (read_cnt < 0)
		{
			lut->hal.block_erase(physical_block);
			lut->empty_block++;
			lut->illegal_block++;
			continue;
		}

		// 检测逻辑块号
		if (spare_head->info.logic != spare_tail->info.logic)
		{
			// 一致表示是合法逻辑号，不一致则擦除该块
			if (!lut->keep_err_logic)
			{
				lut->hal.block_erase(physical_block);
				lut->empty_block++;
			}
			lut->illegal_block++;
			continue;
		}

		// 计算逻辑块号
		if (spare_head->info.logic < lut->logic_block_amount)
		{
			lut_spare_type *spold_head = (lut_spare_type *)&lut->buff[64];
			lut_spare_type *spold_tail = (lut_spare_type *)&lut->buff[96];

			// 有效逻辑块号
			// 防止一个逻辑号占用多个物理号，脏盘可能出现
			// 块拷贝擦除前恰好断电会出现
			if (lut->tab[spare_head->info.logic] != 0xFFFF)
			{
				uint16_t old_phy_block = lut->tab[spare_head->info.logic];
				// 读 spare 区
				nand_lut_info_sapre_read(lut, old_phy_block, spold_head, spold_tail);

				// info 较大者有效，擦除另外一个
				if (spare_head->info.used_cnt >= spold_head->info.used_cnt)
				{
					// 当前块有效，擦除旧块，并更新逻辑表
					lut->hal.block_erase(old_phy_block);
					lut->tab[spare_head->info.logic] = physical_block;
				}
				else
				{
					// 旧块有效，擦除当前块
					lut->hal.block_erase(physical_block);
				}
				// 必定产生擦除操作，空块增量
				lut->empty_block++;
			}
			else
			{
				// 逻辑号空，直接分配
				lut->tab[spare_head->info.logic] = physical_block;
				lut->valid_block++;
			}

			// 读取批次号
			nand_lut_sapre_read(lut, physical_block, LUT_PAGE_OFFSET_BATCH, spold_head, spold_tail);
			if (spold_head->batch.batch != UINT32_MAX)
			{
				if (lut->update.batch_now < spold_head->batch.batch)
				{
					lut->update.batch_now = spold_head->batch.batch;
					lut->new_block_next = physical_block;
				}
			}
		}
		else
		{
			if (spare_head->info.logic == 0xFFFF)
			{
				lut->empty_block++;
			}
			else
			{
				if (!lut->keep_err_logic)
				{
					// 逻辑号越界错误，擦除
					lut->hal.block_erase(physical_block);
					lut->empty_block++;
				}
				lut->illegal_block++;
			}
		}
	}

	// 新块位置限定
	if (lut->new_block_next >= lut->block_total)
		lut->new_block_next = 0;

	// 当前批次号递增
	lut->update.batch_now++;

	// update 参数
	lut->update.b_scan_comp = 0;
	lut->update.scan_blk = 0;
	lut->update.b_scan_req = 0;

	// 不更新
	lut->update.b_new_req = 0;

	nand_lut_read_init(lut);
}

/*****************************************************************************
* @brief   nand lut get new block
*****************************************************************************/
uint16_t nand_lut_get_new_block(nand_lut_type *lut)
{
	uint32_t physical_block_addr, cnt;
	uint32_t buff[3];

	//从0块开始搜索
	physical_block_addr = lut->new_block_next;

	for (cnt = 0; cnt < lut->block_total; physical_block_addr++, cnt++)
	{
		// 地址范围
		physical_block_addr %= lut->block_total;

		// 读取 spare部分的前8字节
		lut->hal.read_spare(physical_block_addr * lut->page_per_block, (uint8_t *)buff, 8);

		// 判断是否坏块，或者已分配 全0xFF代表空闲块
		if ((buff[0] == UINT32_MAX) && (buff[1] == UINT32_MAX))
		{
			// 指向当前位置的下一个
			lut->new_block_next = (physical_block_addr + 1) % lut->block_total;
			lut->empty_block--;

			// 返回目标
			return physical_block_addr;
		}
	}

	lut_puts("lut get new block fail!\n");

	return 0xFFFF;
}

/*****************************************************************************
* @brief   nand lut logic erase
*****************************************************************************/
uint8_t nand_lut_block_erase(nand_lut_type *lut, uint16_t logic_block)
{
	lut->hal.block_erase(lut->tab[logic_block]);
	return 0;
}

/*****************************************************************************
* @brief   nand lut bad block mark
*****************************************************************************/
uint16_t nand_lut_bad_block_mark(nand_lut_type *lut, uint16_t physical_block)
{
	int cnt;

	//擦除
	lut->hal.block_erase(physical_block);

	//填充数据
	for (cnt = 0; cnt < (lut->page_main_size + 8); cnt++)
	{
		lut->buff[cnt] = 0;
	}

	//写缓存
	lut->hal.write_cache(0, lut->buff, lut->page_main_size + 8);

	//执行写入-同时写入首页和尾页
	lut->hal.program_exe(physical_block * lut->page_per_block);
	lut->hal.program_exe((physical_block + 1) * lut->page_per_block - 1);

	lut->bad_block++;
	lut->empty_block--;

	lut_print("lut bad block mark @ %4X \n", physical_block);

	return 0;
}

/*****************************************************************************
*  nand lut get new block
*  return : 0 ok,1 eccerr, -1 ext error
*****************************************************************************/
int8_t nand_lut_program_logic_page(
	nand_lut_type *lut,
	uint16_t logic_block,
	uint16_t page_offset,
	uint8_t *buff)
{
	uint8_t b_page_with_spare = 0;
	uint16_t cnt;
	uint8_t rbuff[16];
	uint32_t physical_page;
	lut_spare_type *spare;

	//获取物理页地址
	physical_page = lut->tab[logic_block] * lut->page_per_block + page_offset;

	// spare 管理
	spare = (lut_spare_type *)(&buff[lut->page_main_size]);
	if ((0 == page_offset) || ((lut->page_per_block - 1) == page_offset))
	{
		//块首页写入块信息
		spare->info.bad_mark = 0xFFFF;
		spare->info.lrc = 0xFFFF;
		spare->info.logic = logic_block;
		spare->info.used_cnt = lut->wr_blk_used_cnt;

		b_page_with_spare = 1;
	}
	else if (LUT_PAGE_OFFSET_BATCH == page_offset)
	{
		//batch 页写入块信息
		spare->batch.bad_mark = 0xFFFF;
		spare->batch.lrc = 0xFFFF;
		spare->batch.batch = lut->update.batch_now;

		b_page_with_spare = 2;
	}
	else if (LUT_PAGE_OFFSET_RTM == page_offset)
	{
		//RTM 页写入块信息
		spare->rtm.bad_mark = 0xFFFF;
		spare->rtm.lrc = 0xFFFF;
		spare->rtm.minute = lut->ref_minute;

		b_page_with_spare = 3;
	}
	else
	{
		b_page_with_spare = 0;
	}

	// 写入CACHE
	if (b_page_with_spare)
		lut->hal.write_cache(0, buff, lut->page_main_size + 8);
	else
		lut->hal.write_cache(0, buff, lut->page_main_size);

	// 执行写操作
	lut->hal.program_exe(physical_page);

	// ECC 及 spare 校验
	for (cnt = 0; cnt < 3; cnt++)
	{
		//执行读操作，检测ECC
		lut->hal.read_page(physical_page);

		if (0 != lut->hal.ecc_error_get())
		{
			continue;
		}

		if (b_page_with_spare)
		{
			//读回信息区
			lut->hal.read_cache(lut->page_main_size, rbuff, 8);

			//比对
			if (0 != memcmp(rbuff, &buff[lut->page_main_size], 8))
			{
				continue;
			}
		}

		break;
	}

	//ecc 错误处理
	if (cnt >= 3)
	{
		lut_print("lut page write error @ block %04X offset %02X\n", logic_block, page_offset);
		return 1;
	}

	return 0;
}

/*****************************************************************************
* @brief   nand  get logic block gen
*****************************************************************************/
uint16_t nand_lut_logic_block_req(nand_lut_type *lut, uint16_t logic_block)
{
	uint16_t blk;

	//获取一个新的物理块
	blk = nand_lut_get_new_block(lut);

	if (blk < lut->block_total)
	{
		//块号合法
		lut->tab[logic_block] = blk;
		lut_print("new block : logic = %04X, phy = %04X\n", logic_block, blk);
	}
	else
	{
		//块号非法，说明没有可用物理块
		lut_print("new block fail @ %04X \n", logic_block);
		return 1;
	}

	return 0;
}

/*****************************************************************************
* @brief   block write
*****************************************************************************/
uint8_t nand_lut_block_write(
	nand_lut_type *lut,
	uint16_t logic_block,
	uint8_t (*write_dat_get)(nand_lut_type *lut, uint32_t addr_offset, uint8_t *pdat, uint16_t len))
{
	uint16_t page_offset;
	uint16_t old_phy_blk;
	uint8_t err;
	uint8_t wloop;

	if (logic_block >= lut->logic_block_amount)
		return 1;

	// 获取当前逻辑页信息
	old_phy_blk = lut->tab[logic_block];
	if (old_phy_blk < lut->block_total)
	{
		lut_spare_type *spare_head;
		lut_spare_type *spare_tail;

		// 备份区指针
		spare_head = (lut_spare_type *)&lut->buff[0];
		spare_tail = (lut_spare_type *)&lut->buff[32];

		nand_lut_info_sapre_read(lut, old_phy_blk, spare_head, spare_tail);

		lut->wr_blk_used_cnt = spare_head->info.used_cnt + 1;
	}

	// 为逻辑块分配新物理地址
	if (nand_lut_logic_block_req(lut, logic_block))
	{
		return 1;
	}

	// 写入数据
	err = 0;
	wloop = 0;
	while (wloop < (lut->block_total - lut->logic_block_amount))
	{
		// 擦除块
		nand_lut_block_erase(lut, logic_block);

		// 一页一页写入数据
		for (page_offset = 0; page_offset < lut->page_per_block; page_offset++)
		{
			int8_t wr_err = 0;

			nand_power_wait();

			// 获取要写入的数据
			if (0 == write_dat_get(lut, page_offset * lut->page_main_size, lut->buff, lut->page_main_size))
			{
				wr_err = nand_lut_program_logic_page(lut, logic_block, page_offset, lut->buff);
				
				// 错误检查
				if (wr_err)
				{
					// ecc / spare 错误，准备重写
					lut_print("lut block write verify error @ block %04X\n", logic_block);
					err++;
					break;
				}				
			}
			else
			{
				nand_lut_block_erase(lut, logic_block);
				
				// 外部数据错误，退出
				lut_print("lut block write extern error @ block %04X\n", logic_block);
				return 1;
			}
		}

		// 错误检查
		if (err)
		{
			// 连续错误，标记坏块，并链接新的物理块
			if (err > 3)
			{
				nand_lut_bad_block_mark(lut, lut->tab[logic_block]);
				err = 0; // 重新开始错误计数
				wloop++;
				lut_print("lut block write error cnt > 5 @ block %04X\n", logic_block);

				// 为逻辑块分配新物理地址
				if (nand_lut_logic_block_req(lut, logic_block))
				{
					return 1;
				}
			}
		}
		else
		{
			// 无错误，表示操作成功，退出
			lut_print("lut block write ok @ block %04X\n", logic_block);
			
			// 擦除旧物理块
			if (old_phy_blk != 0xFFFF)
			{
				lut->hal.block_erase(old_phy_blk);
			}

			// 批次临时增量1，update manager会重新扫描设置
			lut->update.batch_now++;			
			break;
		}
	}

	nand_lut_read_init(lut);

	return 0;
}

/*****************************************************************************
* @brief   nand read
*****************************************************************************/
uint8_t nand_lut_page_read(nand_lut_type *lut, uint32_t logic_page_start, uint8_t *pdat, uint16_t page_len)
{
	uint16_t page_cnt;

	uint32_t physical_page, logic_page_addr;
	uint32_t logic_block, page_offset;

	for (page_cnt = 0; page_cnt < page_len; page_cnt++)
	{
		// 地址范围与读取长度检测
		if (logic_page_start + page_cnt >= lut->logic_block_amount * lut->page_per_block)
		{
			memset(pdat, 0xff, lut->page_main_size);
			continue;
		}

		//逻辑页地址计算
		logic_page_addr = logic_page_start + page_cnt;

		//逻辑块页地址计算
		logic_block = logic_page_addr / lut->page_per_block;
		page_offset = logic_page_addr % lut->page_per_block;

		//物理块地址合法性检查
		if (lut->tab[logic_block] >= lut->block_total)
		{
			// 非法页，填充空数据
			memset(pdat, 0xff, lut->page_main_size);
			pdat += lut->page_main_size;
			continue;
		}

		//物理页地址
		physical_page = lut->tab[logic_block] * lut->page_per_block + page_offset;

		//执行读操作，检测ECC
		if (lut->page_read_old != physical_page)
			lut->hal.read_page(physical_page);
		lut->page_read_old = physical_page;

		if (0 != lut->hal.ecc_error_get())
		{
			//ecc 校验错误
		}

		//读取cache
		lut->hal.read_cache(0, pdat, lut->page_main_size);
		pdat += lut->page_main_size;
	}

	return 0;
}

/*****************************************************************************
* @brief   page read
*****************************************************************************/
uint8_t nand_lut_inp_read(nand_lut_type *lut, uint32_t logic_page, uint16_t cell_offset, int32_t dat_len, uint8_t *pdat)
{
	int32_t len_rd, len_remain;
	uint32_t physical_page;
	uint32_t logic_block, page_offset;

	// 逻辑块页计算
	logic_block = logic_page / lut->page_per_block; //逻辑块地址计算
	page_offset = logic_page % lut->page_per_block; //块内页地址偏移

	// 开始读
	len_remain = dat_len;

	while (len_remain > 0)
	{
		// 本页读取长度
		len_rd = lut->page_main_size - cell_offset;
		if (len_rd > len_remain)
			len_rd = len_remain;

		//物理块地址合法性检查
		if (lut->tab[logic_block] < lut->block_total)
		{
			// 物理页计算
			physical_page = lut->tab[logic_block] * lut->page_per_block + page_offset;

			// 执行读操作，检测ECC
			if (lut->page_read_old != physical_page)
				lut->hal.read_page(physical_page);
			lut->page_read_old = physical_page;

			if (0 != lut->hal.ecc_error_get())
			{
				//ecc 校验错误
			}

			// 读取cache
			lut->hal.read_cache(cell_offset, pdat, len_rd);
		}
		else
		{
			//非法页，填充空数据
			memset(pdat, 0xff, len_rd);
		}

		// 更新参数信息
		len_remain -= len_rd;
		pdat += len_rd;
		cell_offset = 0;
		page_offset++;
		if (page_offset >= lut->page_per_block)
		{
			page_offset = 0;
			logic_block++;
		}
	}

	return 0;
}

/*****************************************************************************
* @brief   logic address read
*****************************************************************************/
uint8_t nand_lut_addr_read(nand_lut_type *lut, uint32_t addr, int32_t dat_len, uint8_t *pdat)
{
	uint32_t logic_page, cell_offset;

	// 页-偏移计算
	logic_page = addr / lut->page_main_size;
	cell_offset = addr % lut->page_main_size;

	return nand_lut_inp_read(lut, logic_page, cell_offset, dat_len, pdat);
}

/*****************************************************************************
* @brief   read init
*****************************************************************************/
uint8_t nand_lut_read_init(nand_lut_type *lut)
{
	lut->page_read_old = UINT32_MAX;

	return 0;
}

/*****************************************************************************
* @brief   update block dat get
*****************************************************************************/
uint8_t lut_update_write_dat_get(nand_lut_type *lut, uint32_t addr_offset, uint8_t *pdat, uint16_t len)
{
	uint32_t physical_page = lut->update.old_phy_block * lut->page_per_block + addr_offset / lut->page_main_size;

	lut->hal.read_page(physical_page);

	//读取cache
	lut->hal.read_cache(0, pdat, lut->page_main_size);

	lut->page_read_old = UINT32_MAX;

	return 0;
}

/*****************************************************************************
* @brief   为逻辑块重分配一个新物理块
*****************************************************************************/
uint8_t nand_lut_block_remap(nand_lut_type *lut, uint16_t logic_blk)
{
	// 逻辑号合法则更新
	if (logic_blk < lut->logic_block_amount)
	{
		// 记录当前物理块
		lut->update.old_phy_block = lut->tab[logic_blk];
		// 写数据
		nand_lut_read_init(lut);
		nand_lut_block_write(lut, logic_blk, lut_update_write_dat_get);
		nand_lut_read_init(lut);
	}
	else
	{
		return -1;
	}

	return 0;
}

/*****************************************************************************
* @brief   update manager，适用于长时间连续通电设备
*****************************************************************************/
uint8_t nand_lut_update_manager(nand_lut_type *lut)
{
	uint8_t minute_now = lut->ref_minute & 0xFF;

	// 执行更新
	if (lut->update.b_scan_comp && lut->update.b_new_req)
	{
		nand_lut_block_remap(lut, lut->update.logic_batch_min);

		// 更新信息
		lut->update.b_new_req = 0;
		lut->update.b_scan_comp = 0;

		lut->update.logic_batch_min = 0;
		lut->update.minute_cnt = 0;
	}

	// 搜索最早的数据块
	if (lut->update.b_scan_req)
	{
		lut_spare_type *spare;
		lut_spare_type *spare_2;

		// 扫描初值
		if (0 == lut->update.scan_blk)
		{
			lut->update.batch_max = 0;
			lut->update.batch_min = UINT32_MAX;
			lut->update.logic_batch_min = LUT_LOGIC_NULL;
		}

		// 备份区指针
		spare = (lut_spare_type *)&lut->buff[0];
		spare_2 = (lut_spare_type *)&lut->buff[32];
		if (lut->tab[lut->update.scan_blk] != LUT_LOGIC_NULL)
		{
			nand_lut_sapre_read(lut, lut->tab[lut->update.scan_blk], LUT_PAGE_OFFSET_BATCH, spare, spare_2);
			if (spare->batch.batch != UINT32_MAX)
			{
				// 批次号最小值
				if (spare->batch.batch < lut->update.batch_min)
				{
					lut->update.batch_min = spare->batch.batch;
					lut->logic_block_amount = lut->tab[lut->update.scan_blk];
				}
				// 批次号最大值
				if (spare->batch.batch > lut->update.batch_max)
				{
					lut->update.batch_max = spare->batch.batch;
				}
			}
		}

		// 搜索计数，结束后设置ready标记
		lut->update.scan_blk++;
		if (lut->update.scan_blk >= lut->logic_block_amount)
		{
			lut->update.b_scan_req = 0;
			lut->update.scan_blk = 0;
			if (lut->update.logic_batch_min != LUT_LOGIC_NULL)
			{
				// 当前批次设置为最大批次+1
				lut->update.batch_now = lut->update.batch_max + 1;
				lut->update.b_scan_comp = 1;
			}
		}
	}

	// 更新请求生成
	if (minute_now != lut->update.minute_old)
	{
		lut->update.minute_cnt++;
		lut->update.minute_old = minute_now;

		if (lut->update_period < 60)
			lut->update_period = 60;

		// 连续运行产生一次更新信号
		if (lut->update.minute_cnt > lut->update_period)
		{
			lut->update.minute_cnt = 0;

			// 开始扫描
			lut->update.b_scan_comp = 0;
			lut->update.scan_blk = 0;
			lut->update.b_scan_req = 1;
			//扫描后直接更新
			lut->update.b_new_req = 1;
		}
	}

	return 0;
}
/*****************************************************************************
* @brief   update manager
******************************************************************************
* 外部管理变量 :
* update.new_req
* update.b_scan_req
* 
******************************************************************************
* END
*****************************************************************************/
